#include <stdio.h>
#include <stdlib.h>
#include "fonctions.h"
#include <time.h>



void purger(void) //vide le buffer clavier pour ne pas entrer dans une boucle infinie si l'utilisateur rentre une lettre lors d'une saisie scanf
{
    char c;
    while ((c = getchar()) != '\n' && c != EOF);
}

void Afficher(int** Tab, int size)  //Affiche la grille
{
    int i,j;
    for (i=0; i<=size-1; i++)
    {
        for (j=0; j<=size-1;j++)
        {
            if (Tab[i][j]==1) printf("X "); //cellules vivantes représentées par X
            else printf("- "); //cellules mortes représentées par -
        }
        printf("\n"); //on passe à la ligne suivante de la grille
    }
}

void Interface(int** Tab,int size)
{
    system(CLEAR); //nettoyer la console
    printf("Nouvelle grille (g) Lancer (l) Stopper (s) Suivant (n) Options (o)\n Vider (v) Editer (e) Importer (i) Exporter (x) Quitter(q)\n\n"); //Affiche les actions disponibles
    Afficher(Tab,size);
}
void Options(int death[8], int birth[8], int cyclique) //affiche le menu des options
{
    int i;
    system(CLEAR);
    printf("Options\n1.Ajuster conditions de naissance :");
    for (i=0;i<=8;i++)
    {
        if (birth[i]==1)
        {
            printf(" %d ",i);
        }
    }
    printf("\n2.Ajuster conditions de mort :");
    for (i=0;i<=8;i++)
    {
        if (death[i]==1)
        {
            printf(" %d ",i);
        }
    }
    printf("\n3.Passer en fonctionnement ");
    if (cyclique==1)
    {
        printf("non cyclique\n");
    }
    else
    {
        printf("cyclique\n");
    }
    printf("4.Retour\n");

}
int Conditions(int sum, int tableau[8])//vérifie si les conditions sont vérifiées selon les options spécifiées par l'utilisateur
{
    int i;
    int condition=0;
    for ( i = 0 ; i<=8 ; i++ )
    {
        if ( tableau[i] == 1 && sum == i )
        {
            condition++;
        }
    }
    return condition;
}



void Suivant(int** Tab, int** Tabn, int size, int birth[8], int death[8], int cyclique) //prend en entrée tableau Tab au temps T et renvoie en sortie Tabn au temps T+1
{
    int i,j,condition;
    if ( cyclique == 0 )
    { //fonctionnement non cyclique
        for ( i = 0 ; i <= size-1 ; i++ )
        {
            for ( j = 0 ; j <= size-1; j++ )
            {
                int sum = 0; //on vérifie l'état des cellules alentoures sans déborder du tableau
                if ( i+1 <= size-1 )
                {
                    sum = sum + Tab[i+1][j]; /*cellule ... à droite*/
                    if (j-1>=0) sum = sum + Tab[i+1][j-1]; /*en haut à droite */
                    if (j+1<=size-1) sum = sum + Tab[i+1][j+1]; /*en bas à droite*/
                }
                if ( i-1 >= 0 )
                {
                    sum = sum + Tab[i-1][j]; /*à gauche */
                    if (j-1>=0) sum = sum + Tab[i-1][j-1]; /*en haut à gauche*/
                    if (j+1<=size-1)  sum = sum + Tab[i-1][j+1]; /*en bas à gauche*/
                }
                if ( j+1 <= size-1 ) sum = sum + Tab[i][j+1]; //en bas
                if ( j-1 >= 0 ) sum = sum + Tab[i][j-1]; // en haut

                if ( Tab[i][j] == 1 )
                {
                    condition = Conditions(sum,death);
                    if (condition==0) Tabn[i][j] = 0; //si une cellule vivante ne remplie pas les conditions, elle meurt à t+1
                }
                if ( Tab[i][j] == 0 )
                {
                    condition = Conditions(sum,birth);
                    if ( condition != 0 )  Tabn[i][j] = 1; //si une cellule morte remplie conditions, elle vie à t+1
                }
            }
        }
    }
    else { //fonctionnement cyclique
        for (i=0; i<=size-1; i++)
        {
            for (j=0; j<=size-1;j++)
            {
                int sum=0;
                sum = Tab[(i+1) % size][j] + Tab[(i-1+size) % size][j] + Tab[i][(j-1+size) % size] + Tab[i][(j+1) % size]+ Tab[(i+1) % size][(j+1) % size]+ Tab[(i-1+size) % size][(j+1) % size]+ Tab[(i+1) % size][(j-1+size) % size]+ Tab[(i-1+size) % size][(j-1+size) % size];

                if (Tab[i][j] == 1)
                {
                    condition = Conditions(sum,death);
                    if (condition==0) Tabn[i][j] = 0; //si une cellule vivante ne remplie pas les conditions, elle meurt à t+1
                }
                if (Tab[i][j] == 0)
                {
                    condition = Conditions(sum,birth);
                    if (condition!=0) Tabn[i][j] = 1; //si une cellule morte remplie conditions, elle vie à t+1
                }
            }
        }
    }
}


void Step(int** Tab, int** Tabn, int size, int birth[8], int death[8], int cyclique){ //Effectue un cycle d'évolution
    int i,j;
    for (i=0; i<=size-1; i++)
    {
        for (j=0; j<=size-1;j++)
        {
        Tabn[i][j]=Tab[i][j];
        }
    }//recopie la grille dans nouveau tableau au temps t+1

    Suivant(Tab,Tabn,size,birth,death,cyclique);//on lance l'algorithme

    for (i=0; i<=size-1; i++)
    {
        for (j=0; j<=size-1;j++)
        {
        Tab[i][j]=Tabn[i][j];
        }
    } //Tabn devient le temps de référence T, on remplace donc Tab par Tabn

    Interface(Tab,size);
}

void Aleatoire(int** Tab,int size){ //remplie le tableau aléatoirement avec des cellules mortes ou vivantes et l'affiche
    int i,j;
	srand(time(NULL));
    for (i=0; i<=size-1; i++)
    {
        for (j=0; j<=size-1;j++)
            {
            Tab[i][j]=(rand() % 2);
            }
    }
Interface(Tab,size);
}


int Exporter(int** Tab,int size){
    FILE *f_out;
    int i;
    if ((f_out = fopen("savefile","w")) == NULL)
    {
      return(EXIT_FAILURE);
    }
    for (i=0;i<=size-1;i++){
        fwrite(Tab[i], size * sizeof(int), 1, f_out);
    }
    fclose(f_out);
    return 0;
}

int Importer(int** Tab,int size)
{
    FILE *f_in;
    int i;
    if ((f_in = fopen("savefile", "r")) == NULL) //si l'ouverture du fichier n'a pas marché, on retourne code erreur
    {
        return(EXIT_FAILURE);
    }
    for (i=0;i<=size-1;i++)
    {
        fread(*(Tab+i), size * sizeof(int), 1, f_in);
    }
    if((int) ftell(f_in) != (size*size*4)) //si le fichier n'a pas la taille attendue (par ex généré avec grille de taille différente), on retourne code erreur
    {
        return(EXIT_FAILURE);
    }
    fclose(f_in);
    return 0;
}
